package com.egaleye.core.exception;

import com.egaleye.core.response.CodeEnum;
import com.egaleye.core.response.RestfulResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.io.IOException;

/**
 * 通用全局异常处理器
 *
 * @author  tangkaijun
 * @version 2021/10/19
 * @since jdk1.8
 */
@Slf4j
@RestControllerAdvice(basePackages = {"com.egaleye"})
public class GlobalExceptionHandler {

    /**
     * 缺少请求参数
     *
     * @param e 缺少请求参数异常
     * @return RestfulResponse 异常响应结果
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public RestfulResponse<Object> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        log.error("缺少请求参数{}", e.getParameterName());
        return new RestfulResponse<>(CodeEnum.BAD_REQUEST).message(String.format("缺少请求参数，[%s]", e.getParameterName()));
    }

    /**
     * 请求信息不可读异常
     *
     * @param e 请求不可读异常
     * @return RestfulResponse 异常响应结果
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public RestfulResponse<Object> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        log.error("请求信息不可读", e);
        return new RestfulResponse<>(CodeEnum.BAD_REQUEST).message("请求信息不可读");
    }

    /**
     * 参数校验异常
     *
     * @param e 参数校验异常
     * @return RestfulResponse 异常响应结果
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public RestfulResponse<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        BindingResult result = e.getBindingResult();
        FieldError error = result.getFieldError();
        String field = error.getField();
        String code = error.getDefaultMessage();
        log.error("参数验证失败-{}:{}", field, code, e);
        return new RestfulResponse<>(CodeEnum.BAD_REQUEST).message(String.format("参数验证失败， %s:%s", field, code));
    }

    /**
     * 参数绑定异常
     *
     * @param e 参数绑定异常
     * @return RestfulResponse 异常响应结果
     */
    @ExceptionHandler(BindException.class)
    public RestfulResponse<Object> handleBindException(BindException e) {
        BindingResult result = e.getBindingResult();
        FieldError error = result.getFieldError();
        String field = error.getField();
        String code = error.getDefaultMessage();
        log.error("参数绑定失败-{}:{}", field, code, e);
        return new RestfulResponse<>(CodeEnum.BAD_REQUEST).message(String.format("参数绑定失败，%s:%s", field, code));
    }

    /**
     * 请求方法不支持异常
     *
     * @param e 请求方法不支持异常
     * @return RestfulResponse 异常响应结果
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public RestfulResponse<Object> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        log.error("不支持当前请求方法{}", e.getMethod());
        return new RestfulResponse<>(CodeEnum.METHOD_NOT_ALLOWED).message(e.getMethod());
    }

    /**
     * 请求媒体类型异常
     *
     * @param e 请求媒体类型异常
     * @return RestfulResponse 异常响应结果
     */
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public RestfulResponse<Object> handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
        log.error("不支持当前媒体类型{}", e.getContentType());
        return new RestfulResponse<>(CodeEnum.UNSUPPORTED_MEDIA_TYPE).message(String.format("不支持当前媒体类型 [%s]", e.getContentType()));
    }

    /**
     * 不合法参数异常
     *
     * @param e 不合法参数异常
     * @return RestfulResponse 异常响应结果
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public RestfulResponse<Object> handleIllegalArgumentException(IllegalArgumentException e) {
        log.error("存在不合法的参数", e);
        return new RestfulResponse<>(CodeEnum.BAD_REQUEST).message("存在不合法的参数");
    }

    /**
     * 空指针异常
     *
     * @param e 空指针异常
     * @return RestfulResponse 异常响应结果
     */
    @ExceptionHandler(NullPointerException.class)
    public RestfulResponse<Object> handleNullPointerException(NullPointerException e) {
        return buildThrowableResponse("空指针异常", CodeEnum.INTERNAL_SERVER_ERROR, e);
    }

    /**
     * 类型转换异常
     *
     * @param e 类型转换异常
     * @return RestfulResponse 异常响应结果
     */
    @ExceptionHandler(ClassCastException.class)
    public RestfulResponse<Object> handleClassCastException(ClassCastException e) {
        return buildThrowableResponse("类型转换异常", CodeEnum.INTERNAL_SERVER_ERROR, e);
    }

    /**
     * IO异常
     *
     * @param e IO异常
     * @return RestfulResponse 异常响应结果
     */
    @ExceptionHandler(IOException.class)
    public RestfulResponse<Object> handleIOException(IOException e) {
        return buildThrowableResponse("IO异常", CodeEnum.INTERNAL_SERVER_ERROR, e);
    }

    /**
     * 未知方法异常
     *
     * @param e 未知方法异常
     * @return RestfulResponse 异常响应结果
     */
    @ExceptionHandler(NoSuchMethodException.class)
    public RestfulResponse<Object> handleNoSuchMethodException(NoSuchMethodException e) {
        return buildThrowableResponse("未知方法异常", CodeEnum.UNKNOWN_ERROR, e);
    }

    /**
     * 数组越界异常
     *
     * @param e 数组越界异常
     * @return RestfulResponse 异常响应结果
     */
    @ExceptionHandler(IndexOutOfBoundsException.class)
    public RestfulResponse<Object> indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException e) {
        return buildThrowableResponse("数组越界异常", CodeEnum.INTERNAL_SERVER_ERROR, e);
    }

    /**
     * 基础异常
     *
     * @param e 基础异常类
     * @return RestfulResponse<Void> 异常响应结果
     */
    @ExceptionHandler(BaseException.class)
    public RestfulResponse<Object> handleBaseException(BaseException e) {
        return buildRestfulResponse(String.format("[%s] 处理异常: ", e.getApp()), e);
    }

    /**
     * 运行时异常
     *
     * @param e 运行时异常
     * @return RestfulResponse 异常响应结果
     */
    @ExceptionHandler(Exception.class)
    public RestfulResponse<Object> handleException(Exception e) {
        return buildThrowableResponse("运行时异常", CodeEnum.INTERNAL_SERVER_ERROR, e);
    }

    /**
     * 系统异常
     *
     * @param e 系统异常
     * @return RestfulResponse 异常响应结果
     */
    @ExceptionHandler(Throwable.class)
    public RestfulResponse<Object> handleThrowable(Throwable e) {
        return buildThrowableResponse("系统异常", CodeEnum.UNKNOWN_ERROR, e);
    }

    /**
     * 构建基础异常响应结果
     *
     * @param message 异常提示信息
     * @param e       基础异常
     * @return 异常响应结果
     */
    protected RestfulResponse<Object> buildRestfulResponse(String message, BaseException e) {
        log.error(message, e);
        return new RestfulResponse<>(e.getCodeEnum()).message(e.getArgs());
    }

    /**
     * 构建异常响应结果
     *
     * @param message  异常提示信息
     * @param codeEnum 错误码
     * @param e        异常
     * @return 异常响应结果
     */
    protected RestfulResponse<Object> buildThrowableResponse(String message, CodeEnum codeEnum, Throwable e) {
        log.error(message, e);
        return new RestfulResponse<>(codeEnum).message(message);
    }

}
